;
; LOD Player Version 2
;
F1LO	= $FF0E
F1HI	= $FF12
F2LO	= $FF0F
F2HI	= $FF10

freqs = $0500

freqs_add
	DB 07,57,54,51, 48,45,43,40, 38,36,34,32 ; 00
	DB 31,28,27,25, 24,23,21,21, 19,18,17,16 ; 12
	DB 15,14,14,12, 12,12,10,10, 10,09,08,08 ; 24
	DB 08,07,07,06, 06,06,05,05, 05,04,05,04 ; 36
	DB 03,04,03,04, 03,02,03,03, 02,02,02,02 ; 48
	DB 02,02,02,02+24			 ; 60 (63=off)
	
; Variables
base = $40
PCH1		= base + $00	; channel data pattern pointers
PCH2		= base + $02
;PCH3		= base + $04
CH1		= base + $06	; channel data pointers
CH2		= base + $08
;CH3		= base + $0A

NOTE1		= base + $0C	; note counters
NOTE2		= base + $0D
;NOTE3		= base + $0E
NOTELEN1	= base + $0F	; current note lengths
NOTELEN2	= base + $10
;NOTELEN3	= base + $11

INS_TYPE1	= base + $12
INS_TYPE2	= base + $13
;INS_TYPE3	= base + $14
TONE1		= base + $15
TONE2		= base + $16
TONE_PREV1	= base + $17
ARP_CNT1	= base + $18
ARP_CNT2	= base + $19
;ARP_CNT3	= base + $1A

NOISE		= base + $1A
VOL_TAB		= base + $1B ; 16 bit

VOLUME		= base + $1D 
VOLTAB_CNT	= base + $1E

; COMMAND BYTES

END_MARK	= $FF
RETRIG		= $FE
SET_VOLTAB	= $FD
SET_SLIDE	= $FC
SET_ARP		= $FB
SETINS		= $F0
SETVOL		= $E0
SETLEN		= $40

; Constants
base_note = 0 ; shift to Gi0
C0	= base_note + 0
Ci0	= base_note + 1	
D0	= base_note + 2
Di0	= base_note + 3
E0	= base_note + 4
F0	= base_note + 5
Fi0	= base_note + 6
G0	= base_note + 7
Gi0	= base_note + 8
A0	= base_note + 9
Ai0	= base_note + 10
B0	= base_note + 11

C1	= base_note + 12
Ci1	= base_note + 13
D1	= base_note + 14
Di1	= base_note + 15
E1	= base_note + 16
F1	= base_note + 17
Fi1	= base_note + 18
G1	= base_note + 19
Gi1	= base_note + 20
A1	= base_note + 21
Ai1	= base_note + 22
B1	= base_note + 23

C2 = base_note + 24
Ci2 = base_note + 25
D2 = base_note + 26
Di2 = base_note + 27
E2 = base_note + 28
F2 = base_note + 29
Fi2 = base_note + 30
G2 = base_note + 31
Gi2 = base_note + 32
A2 = base_note + 33
Ai2 = base_note + 34
B2 = base_note + 35

C3 = base_note + 36
Ci3 = base_note + 37
D3 = base_note + 38
Di3 = base_note + 39
E3 = base_note + 40
F3 = base_note + 41
Fi3 = base_note + 42
G3 = base_note + 43
Gi3 = base_note + 44
A3 = base_note + 45
Ai3 = base_note + 46
B3 = base_note + 47

C4 = base_note + 48
Ci4 = base_note + 49
D4 = base_note + 50
Di4 = base_note + 51
E4 = base_note + 52
F4 = base_note + 53
Fi4 = base_note + 54
G4 = base_note + 55
Gi4 = base_note + 56
A4 = base_note + 57
Ai4 = base_note + 58
B4 = base_note + 59

C5 = base_note + 60
Ci5 = base_note + 61
D5 = base_note + 62

OFF = 63

;-----
          
	ALIGN 256         
PLAYER_FREQ_INIT
	;         
	; *** Freq init
	;              
	LDA #$00
	CLC
	ADC freqs_add
	STA freqs
	LDA #$00
	ADC #$00
	STA freqs+1
	;
	LDX #$00
	LDY #$01
	;
freq_init
	LDA freqs,x
	CLC
	ADC freqs_add,y
	STA freqs+2,x
	INX
	LDA freqs,x
	ADC #$00
	STA freqs+2,x
	INX
	INY
	CPY #64
	BNE freq_init
	;
PLAYER_INIT
	JSR reset_ch1
	JSR reset_ch2
	;JSR reset_ch3
	;
	JSR advance_ch1
	JSR advance_ch2
	;JSR advance_ch3
	;
	LDX #$FF
	STX VOLTAB_CNT
	INX
	STX NOTE1
	STX NOTE2
	;STX NOTE3
	INX
	STX NOTELEN1
	STX NOTELEN2
	;STX NOTELEN3
	;
	LDA #vol_default & 255
	STA VOL_TAB
	LDA #vol_default >> 8
	STA VOL_TAB+1
	;
	LDA #$00	; max
	STA VOLUME
	;
	RTS

res_1	JSR reset_ch1
	;
advance_ch1
	LDY #$01
	LDA (PCH1),y	; HI byte
	BEQ res_1
	STA CH1 + 1
	DEY
	LDA (PCH1),y	; LO byte
	STA CH1
	INC PCH1
	INC PCH1
	RTS
	
;set_ch1
;	STX SPCH1
;	STY SPCH1 + 1
;	RTS

reset_ch1
	;LDX SPCH1
	;LDY SPCH1 + 1
	LDX #Channel1 & 255
	LDY #Channel1 >> 8
	STX PCH1
	STY PCH1 + 1
	RTS
	
reset_ch2
	;LDX SPCH2
	;LDY SPCH2 + 1
	LDX #Channel2 & 255
	LDY #Channel2 >> 8
	STX PCH2
	STY PCH2 + 1
	RTS
	
;reset_ch3
;	;LDX SPCH2
;	;LDY SPCH2 + 1
;	LDX #Channel3 & 255
;	LDY #Channel3 >> 8
;	STX PCH3
;	STY PCH3 + 1
;	RTS
	
res_2	JSR reset_ch2
	;
advance_ch2
	LDY #$01
	LDA (PCH2),y
	BEQ res_2
	;
	STA CH2 + 1
	;
	DEY
	LDA (PCH2),y
	STA CH2
	;
	INC PCH2
	INC PCH2
	;
	RTS
	
;res_3	JSR reset_ch3
;	;
;advance_ch3
;	LDY #$01
;	LDA (PCH3),y
;	BEQ res_3
;	;
;	STA CH3 + 1
;	;
;	DEY
;	LDA (PCH3),y
;	STA CH3
;	;
;	INC PCH3
;	INC PCH3
;	;
;	RTS

;set_ch2
;	STX SPCH2
;	STY SPCH2 + 1
;	RTS

	;
	;##################
	;

PLAYER
	;------------------
	;JMP *
	INC NOTE1
	INC ARP_CNT1
	;
	LDA NOTE1
	CMP NOTELEN1
	BEQ next_note1
	JMP channel2
	;
new_pattern1
	JSR advance_ch1
	;
next_note1
	LDY #$00
	STY NOTE1		; reset note counter
	;STY TICK1
	STY ARP_CNT1		; reset arp counter
	;
	LDA (CH1),y		; get byte
	INY
	;
	CMP #END_MARK		; $FF goes to new pattern
	BEQ new_pattern1
	;
;	CMP #RETRIG
;	BNE pl_10
;	;
;	LDA #$80
;	STA click+1
;	;
;	LDA (CH1),y		; get byte
;	INY
;	;
;pl_10	CMP #$FD
;	BNE pl_11
;	;
;	LDA #$FF		; reset voltab counter
;	STA VOLTAB_CNT
;	STA VOLUME		; disable SET volume
;	;
;	LDA (CH1),y		; get lo byte
;	STA VOL_TAB
;	INY
;	;
;	LDA (CH1),y		; get hi byte
;	STA VOL_TAB+1
;	INY
;	;
;	LDA (CH1),y		; get byte
;	INY
;	;
;pl_11	
;	CMP #$FC
;	BNE pl_12
;	;
;	LDA (CH1),y		; get SLIDE lo byte
;	STA slide
;	INY
;	;
;	LDA (CH1),y		; get SLIDE hi byte
;	STA slide+1
;	INY
;	;
;	LDA (CH1),y		; get byte
;	INY
;	;
;pl_12	
	CMP #SET_ARP
	BNE pl_14
	;
	LDA (CH1),y		; get arp lo byte
	STA arp_ptr1+1
	INY
	;
	LDA (CH1),y		; get arp hi byte
	STA arp_ptr1+2
	INY
	;
	LDA (CH1),y		; get byte
	INY
	;
pl_14	CMP #$F0		; instrument change?
	BCC pl_01
	;
	AND #$0F		; keep lower 4 bits
	STA INS_TYPE1   	; store instrument type
	;
	LDA (CH1),y		; get byte
	INY
	;
pl_01	CMP #$E0
	BCC pl_05
	;
	LDA VOLUME
	CLC
	ADC #$09
	;AND #$0F
	;TAX
	;LDA mul9,x
	STA VOLUME		; store direct volume set value
	;
	LDA (CH1),y		; get byte
	INY
	;
pl_05	CMP #$40		; set note length?
	BCC pl_02
	;
	SEC
	SBC #$40
	STA NOTELEN1
	;
	LDA (CH1),y
	INY
	;
pl_02	; - store note!
	;
	LDX TONE1		; keep previous
	STX TONE_PREV1
	STA TONE1
	;
	; --- advance pointer
	;
	TYA
	CLC
	ADC CH1
	STA CH1
	BCC noi_1
	INC CH1 + 1
noi_1	;
	;
	; -----------------------------------------------------------------
	;
channel2
	INC NOTE2
	INC ARP_CNT2
	;
	LDA NOTE2
	CMP NOTELEN2
	BEQ next_note2
	BNE channel3
	;
new_pattern2
	JSR advance_ch2
	;
next_note2
	LDY #$00
	STY NOTE2		; reset note counter
	;STY TICK2
	STY ARP_CNT2		; reset arp counter
	;
	LDA (CH2),y		; get byte
	INY
	;
	CMP #END_MARK		; $FF goes to new pattern
	BEQ new_pattern2
	;
	CMP #SET_ARP
	BNE pl_24
	;
	LDA (CH2),y		; get arp lo byte
	STA arp_ptr2+1
	INY
	;
	LDA (CH2),y		; get arp hi byte
	STA arp_ptr2+2
	INY
	;
	LDA (CH2),y		; get byte
	INY
	;
pl_24	CMP #$F0		; instrument change?
	BCC pl_21
	;
	AND #$0F		; keep lower 4 bits
	STA INS_TYPE2   	; store instrument type
	;
	LDA (CH2),y		; get byte
	INY
	;
pl_21	
;	CMP #$E0
;	BCC pl_25
;	;
;	AND #$0F
;	STA VOLUME
;	;
;	LDA (CH2),y		; get byte
;	INY
;	;
;pl_25	
	CMP #$40		; set note length?
	BCC pl_22
	;
	SEC
	SBC #$40
	STA NOTELEN2
	;
	LDA (CH2),y
	INY
	;
pl_22	; - store note!
	;
	LDX TONE2
	;STX TONE_PREV2
	STA TONE2
	;
	; --- advance pointer
	;
	TYA
	CLC
	ADC CH2
	STA CH2
	BCC noi_2
	INC CH2 + 1
noi_2	;
	;
	; -----------------------------------------------------------------
	;
channel3
;	INC NOTE3
;	INC ARP_CNT3
;	;
;	LDA NOTE3
;	CMP NOTELEN3
;	BEQ next_note3
;	BNE pl_50
;	;
;new_pattern3
;	JSR advance_ch3
;	;
;next_note3
;	LDY #$00
;	STY NOTE3		; reset note counter
;	;STY TICK3
;	STY ARP_CNT3		; reset arp counter
;	;
;	LDA (CH3),y		; get byte
;	INY
;	;
;	CMP #END_MARK		; $FF goes to new pattern
;	BEQ new_pattern3
;	;
;pl_34	CMP #$F0		; instrument change?
;	BCC pl_31
;	;
;	AND #$0F		; keep lower 4 bits
;	STA INS_TYPE3   	; store instrument type
;	;
;	LDA (CH3),y		; get byte
;	INY
;	;
;pl_31	CMP #$40		; set note length?
;	BCC pl_32
;	;
;	SEC
;	SBC #$40
;	STA NOTELEN3
;	;
;	LDA (CH3),y
;	INY
;	;
;pl_32	; - store note!
;	;
;	LDX TONE3
;	;STX TONE_PREV3
;	STA TONE3
;	;
;	; --- advance pointer
;	;
;	TYA
;	CLC
;	ADC CH3
;	STA CH3
;	BCC noi_3
;	INC CH3 + 1
;noi_3	;     
	;
	;    
pl_50	LDY VOLTAB_CNT
	INY
	LDA (VOL_TAB),y
	BPL noi_v		; check for $FF
	LDY #$00		; reached, so warp
noi_v	STY VOLTAB_CNT
	;
	; --- SOUND PROCESSING
	;
PLAYER_SOUND
	LDA #$20
	STA NOISE
	;
	LDX #$00		; channel 0
	JSR sound
	;
	STA F1LO
	STY F1HI_x+1
	;
	LDA F1HI
	AND #$FC
F1HI_x	ORA #$00
	STA F1HI
	;
	TYA
	CLC
	ADC #$C8
	STA $17E8
	ADC #$10
	STA $17E9
	ADC #$10
	STA $17EA
	ADC #$08
	STA $17EB
	;
	LDX #$01		; channel 1
	JSR sound
	STA F2LO
	STY F2HI
	;
	; ---
	;    
	;INC TICK1
	;INC TICK2
	;
	; ---
	;
	LDA F1LO		; if both channels are quiet, don't set volume
	CMP #$FE
	BNE sv_1
	LDA F2LO
	CMP #$FE
	BEQ sv_2
	;  
sv_1	LDY VOLTAB_CNT
	LDA (VOL_TAB),Y		; nope, read from envelope
	CLC
	ADC VOLUME
	TAY
	LDA volume_map,y
	;
pl_70	ORA #$10
	;
	;ORA #$20
	ORA NOISE
	;
;click	ORA #$00
setvol	STA $FF11
	;
	;LDA #$00
	;STA click+1
	;
sv_2	RTS     
	;
inst_table
	DW normal, arp, bassdrum, snare, glide
	;
sound	;JMP *	
	LDA INS_TYPE1,x
	ASL a
	TAY
	LDA inst_table,y
	STA inst_jump+1
	LDA inst_table+1,y
	STA inst_jump+2
	;
inst_jump
	JMP $0000
	;
normal	LDA TONE1,x		; normal note
lookup	ASL a
	TAX
	LDA freqs,x
	LDY freqs+1,x
	RTS
	
arp	LDA TONE1,x		; extra feature: OFF "knows" not to use arp
	CMP #OFF
	BEQ lookup
	;
	LDY ARP_CNT1,x		; load current arp counter
	;
	CPX #$00		; check which channel
	BEQ arp_ptr1
arp_ptr2
	LDA arpeggio,y		; for channel 2 (self-mod)
	JMP arp_1
arp_ptr1
	LDA arpeggio,y		; for channel 1 (self-mod)
arp_1
	BPL arp_add		; check for negative numbers
	;
	AND #$0F		; low byte is new position
	STA ARP_CNT1,x
	JMP arp			; again!
	;
arp_add
	CLC
	ADC TONE1,x
	JMP lookup
	
;	;
;slider	;
;;	LDA slide
;;	BNE sl_01
;;	DEC slide+1
;;sl_01	DEC slide
;	;  
;	LDA TICK1,x
;	BNE add1
;	;
;	LDA slide
;	LDY slide+1
;	RTS
;	;
;add1	LDA TONE1,x
;	ASL a
;	TAX
;	LDY freqs+1,x
;	LDA freqs,x
;	CLC
;	ADC #$01
;	BCC sl_03
;	INY
;sl_03	RTS
	;
snare	
	LDA #$40		; turn on noise bit
	STA NOISE
	;
	LDA TONE1,x		; look up note freq
	ASL a
	TAY
	;
	LDA NOTE1,x
	ASL a
	TAX
	LDA snare_freq,x	; 16 bit add: add snare freq
	CLC
	ADC freqs,y       
	PHA
	LDA snare_freq+1,x
	ADC freqs+1,y
	TAY
	PLA
	RTS
	
bassdrum
	LDA NOTE1,x
	ASL a
	TAX
	LDA bass_freq,x
	LDY bass_freq+1,x
	RTS              
	
;vibX	LDA NOTE1,x
;	AND #$0F
;	TAY
;	LDA vibrato2,y
;	BMI vib_sub1
;	BPL vib_add

;vib	LDA NOTE1,x
;	AND #$07
;	TAY
;	LDA vibrato,y
;	BMI vib_sub1
;	;
;vib_add
;	STA vib2+1
;	;
;	LDA TONE1,x
;	ASL a
;	TAX
;	LDY freqs+1,x
;	LDA freqs,x
;	CLC
;vib2	ADC #$01
;	BCC vib3
;	INY
;vib3	RTS
;	;
;vib_sub1
;	AND #$7F
;	;      
;	STA vib4+1
;	;
;	LDA TONE1,x
;	ASL a
;	TAX
;	LDY freqs+1,x
;	LDA freqs,x
;	SEC
;vib4	SBC #$01
;	BCS vib5
;	DEY
;vib5	RTS
;
glide_2	JMP normal

glide	LDA NOTE1,x
	BEQ glide_1
	;
	;
	;
	CMP #$02			; change this to determine glide length
	BCS glide_2
	;
	LDA glide_add
	BMI glide_sub
	;
	LDA glide_freq_current
	CLC
	ADC glide_freq_diff
	STA glide_freq_current
	LDA glide_freq_current+1
	ADC glide_freq_diff+1
	STA glide_freq_current+1
	LDA glide_freq_current+2
	ADC glide_freq_diff+2
	STA glide_freq_current+2
	;
	LDA glide_freq_current+1
	LDY glide_freq_current+2
	;
	RTS
	;
glide_sub
	LDA glide_freq_current
	SEC
	SBC glide_freq_diff
	STA glide_freq_current
	LDA glide_freq_current+1
	SBC glide_freq_diff+1
	STA glide_freq_current+1
	LDA glide_freq_current+2
	SBC glide_freq_diff+2
	STA glide_freq_current+2
	;
	LDA glide_freq_current+1
	LDY glide_freq_current+2
	;
	RTS
	;
	; first iteration
	;
glide_1	LDA TONE1,x			; look up destination freq
	ASL a
	TAY
	LDA freqs,y
	STA glide_freq_dest+1
	LDA freqs+1,y   
	STA glide_freq_dest+2
	;
	LDA TONE_PREV1,x		; look up previous freq
	ASL a
	TAY
	LDA freqs,y
	STA glide_freq_current+1
	LDA freqs+1,y   
	STA glide_freq_current+2
	;
	LDA #$00             		; clear low bytes of 24 bit values
	STA glide_freq_dest
	STA glide_freq_current
	STA glide_freq_diff
	;
	LDA TONE1,x
	CMP TONE_PREV1,x
	BCS glide_down
	;
	; up
	;
	LDA glide_freq_dest+1		; diff = dest - current
	SEC
	SBC glide_freq_current+1
	STA glide_freq_diff+1
	LDA glide_freq_dest+2
	SBC glide_freq_current+2
	STA glide_freq_diff+2
	;
	LDA #$00
gl_up	STA glide_add
	;
	LSR glide_freq_diff+2		; 24 bit div routine
	ROR glide_freq_diff+1
	ROR glide_freq_diff		; div2
	;LSR glide_freq_diff+2
	;ROR glide_freq_diff+1
	;ROR glide_freq_diff		; div4
	;LSR glide_freq_diff+2
	;ROR glide_freq_diff+1
	;ROR glide_freq_diff		; div8
	;LSR glide_freq_diff+2
	;ROR glide_freq_diff+1
	;ROR glide_freq_diff
	;
	LDA glide_freq_current+1
	LDY glide_freq_current+2
	;
	RTS

glide_down
	LDA glide_freq_current+1	; diff = current - dest
	SEC
	SBC glide_freq_dest+1
	STA glide_freq_diff+1
	LDA glide_freq_current+2
	SBC glide_freq_dest+2
	STA glide_freq_diff+2
	;
	LDA #$80     
	BNE gl_up			; always jump

glide_freq_current
	DB 0,0,0	; 24 bit values
glide_freq_dest
	DB 0,0,0
glide_freq_diff
	DB 0,0,0
glide_add
	DB 0
;	
;vibrato
;	DB $00,$01,$02,$01
;	DB $00,$81,$82,$81
;	
snare_freq
	;DW $F8,$F0, $E8,$E0, $D8,$D0, $C8,$C0, $A0,$80, $40,$00
	DW $00F0,$00C0, $00FC,$00A0, $00F8,$0080
	;DW $00F4,$0060, $00F0,$0040, $00E0,$0020, $00D0,$0010
	;DW $00F8,$0040, $00F7,$0038, $00F6,$0030, $00F5,$0028, $00F4,$0020, $00F3,$0018, $00F0,$0010
	;
bass_freq
	DW $0204, $0183, $0102, $00C1, $0067, $0024, $0007
	;DW $0183, $00FA, $0067, $0007
	
